package bookhive.catalog;

import net.jxta.id.IDFactory;
import net.jxta.impl.wire.AdvCooker;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.Element;
import net.jxta.document.MimeMediaType;
import net.jxta.document.StructuredDocumentFactory;
import net.jxta.document.XMLDocument;
import net.jxta.pipe.InputPipe;
import net.jxta.pipe.PipeID;
import net.jxta.platform.ModuleClassID;
import net.jxta.platform.ModuleSpecID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.protocol.ModuleSpecAdvertisement;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.document.Advertisement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownServiceException;
import java.util.Properties;
import java.util.Vector;

import bookhive.LibraryPeer;
import bookhive.datasource.DataSource;

public class CatalogPeer extends LibraryPeer {

	public static final String inpipeId = "urn:jxta:uuid-3E3BB0BF4B144C359E348FABA35C49214E3A9A9C2F33450B9E50F4E4B1E80E3D04";

	public static final String moduleSpecId = "urn:jxta:uuid-E9984C6215464F2A937EE9CFF921B2D4CD2F7DA6E40946DAA57CD4A22574744206";

	private PipeAdvertisement ServicePipeAdv = null;

	private DataSource dataSource = null;

	private InputPipe inpipe;

	private Vector<String> handledMessages = null;

	public CatalogPeer(Properties catProp, PeerGroup pg) {
		super(pg);
		catalogProperties = catProp;
		pg.getRendezVousService().startRendezVous();
	}

	public void init() {

		String dataSourceClassName = catalogProperties
				.getProperty("DataSourceClass");
		Class dataSourceClass = null;
		try {
			dataSourceClass = Class.forName(dataSourceClassName);
		} catch (ClassNotFoundException e) {
		}
		if (dataSourceClass == null) {
			System.out.println("Class " + dataSourceClassName
					+ " not found. Exiting...");
			System.exit(1);
		}
		try {
			dataSource = (DataSource) dataSourceClass.newInstance();
		} catch (InstantiationException e) {
			System.out.println("Problem instantiating " + dataSourceClassName);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			System.out.println("Illegal Access to " + dataSourceClassName);
			e.printStackTrace();
		}
		jxtaInit();
		try {
			System.out.println("Creating pipe for catalog service...");
			// CatalogRequestHandler handler = new
			// CatalogRequestHandler(dataSource);
			inpipe = pipes.createInputPipe(ServicePipeAdv);
			// Thread.sleep(5000);
		} catch (Exception ex) {
			System.out.println("Data collection pipe creation failed.");
			return;
		}
		System.out.println("pipe created successfully");

		handledMessages = new Vector<String>();
	}

	private void startRedunder() {
		System.out.println("Catalog PeerID = " + group.getPeerID().toString());
		RedunderPeer r = new RedunderPeer(group, dataSource);
		r.start();
	}

	@Override
	public void run() {
		startService();
	}

	private void startService() {
		// startRedunder();
		System.out.println("service started in " + group.getPeerGroupName()
				+ "\n- - - - - - - - - - - - - - - - - - - -");
		while (true) {
			Message msg;
			try {
				msg = inpipe.waitForMessage();
				MessageElement jxtaWireHeaderMessageElement = msg
						.getMessageElement("JxtaWireHeader");
				try {
					XMLDocument xml = (XMLDocument) StructuredDocumentFactory
							.newStructuredDocument(
									new MimeMediaType("text/xml"),
									jxtaWireHeaderMessageElement.getStream());
					Element el = (Element) xml.getChildren("MsgId")
							.nextElement();
					String id = el.getValue().toString();

					if (handledMessages.contains(id))
						continue;
					if (handledMessages.size() > 20)
						handledMessages.remove(handledMessages.firstElement());
					handledMessages.add(id);
				} catch (IOException e) {
					e.printStackTrace();
				}

				CatalogRequestHandler handler = new CatalogRequestHandler(
						dataSource, msg, pipes, group.getPeerID());

				handler.start();

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}

	private void jxtaInit() {

		if (group != null) {
			discovery = group.getDiscoveryService();
			pipes = group.getPipeService();
		}
		// System.out.println("Look for previously created Pipe Adv, create one
		// if not exist");
		ServicePipeAdv = createInputPipeAdvIfNotExist();

		/***********************************************************************
		 * check for ModuleSpecAdv
		 */
		System.out.print("Checking to see if MSA previously published...");
		if (findModuleSpecAdv() == null) {
			System.out.println(".. MSA not found, need to create it");
			publishModuleSpecAdv(ServicePipeAdv);
		} else
			System.out.println("..found previously published MSA");
	}

	public PipeAdvertisement createInputPipeAdvIfNotExist() {
		Advertisement padv = null;
		if ((padv = findPipeAdv()) != null) {
			// found it
			return (PipeAdvertisement) padv;
		}
		System.out
				.println("Previously published pipe advertisment not found, creating a new one.");
		// create a new one
		PipeAdvertisement pipeAdv;
		pipeAdv = (PipeAdvertisement) AdvertisementFactory
				.newAdvertisement(PipeAdvertisement.getAdvertisementType());
		pipeAdv.setName(servicePipeName);
		pipeAdv.setType(servicePipeType);
		PipeID tpID;
		try {
			tpID = (PipeID) IDFactory.fromURI(new URI(inpipeId));
		} catch (URISyntaxException e) {
			tpID = IDFactory.newPipeID(group.getPeerGroupID());
			// e.printStackTrace();
		}//
		pipeAdv.setPipeID(tpID);

		System.out.println("Locally caching the new pipe advertsiement...");
		try {
			discovery.publish(pipeAdv);
		} catch (Exception ex) {
			System.out.println("Err: " + ex);
		}
		return pipeAdv;
	}

	protected void publishModuleSpecAdv(PipeAdvertisement ServicePipeAdv) {

		ModuleSpecAdvertisement msAdv = null;
		System.out.println("Creating new MSA");

		ModuleSpecID msid = null;
		try {
			msid = AdvCooker.buildModuleSpecID(moduleSpecId);
		} catch (UnknownServiceException e) {
			System.out.println(e.getMessage());
		} catch (MalformedURLException e) {
			System.out.println(e.getMessage());
		}
		if (msid == null) {
			ModuleClassID mcid = IDFactory.newModuleClassID();
			msid = IDFactory.newModuleSpecID(mcid);
		}
		System.out.println("msid=" + msid);

		if (msid != null) {
			msAdv = AdvCooker.buildModuleSpecAdvertisement(msid, // ModuleSpecID
																	// msid,
					ModuleSpecName, // String moduleSpecName,
					"Catalog engine", // String moduleSpecDescription,
					"SIB-SBA Units.it", // String creator,
					"Version 1.0", // String version,
					"http://www.biblio.units.it", // String specURI,
					ServicePipeAdv, // PipeAdvertisement pipeAdv,
					null, // ModuleSpecID proxySpecID,
					null, // ModuleSpecID authorizationSpecID,
					null // StructuredDocument param
					);
			System.out.println("Locally and remotely publish the MSA");
			try {
				discovery.publish(msAdv);
				discovery.remotePublish(msAdv, DiscoveryService.ADV);
			} catch (Exception ex) {
				System.out.println("Err: " + ex);
			}
		}
	}

	public static void main(String[] args) {
		CatalogPeer ct = new CatalogPeer(null, null);
		ct.init();
		// ct.process();
	} // of main()

}